#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include "Mutex.hpp"
#include "Cond.hpp"

namespace BlockQueueModule
{
	using namespace MutexData;
	using namespace CondModule;
	static const int Size = 10;
	template <typename T>
	class BlockQueue
	{
	private:
		bool ISFull() { return _q.size() == _cap; }
		bool ISEmpty() { return _q.empty(); }

	public:
		// 构造列表 ：， ，
		BlockQueue(int cap = Size) : _cap(cap), _cwait_num(0), _pwait_num(0)
		{
		}
		void Equeue(const T &in)
		{
			LockGuard lockguard(_mutex);
			// 你想放数据，就能放数据吗？？生产数据是有条件的！
			// 如果满了就不放
			while (ISFull())
			{
				std::cout << "生产者进入等待..." << std::endl;
				_pwait_num++;
				_production_cond.Wait(_mutex);
				_pwait_num--;
				std::cout << "生产者被唤醒" << std::endl;
			}
			// if(IsFull())不满足 || 线程被唤醒
			_q.push(in); // 生产
			// 肯定有数据,如果消费者队列有则唤醒
			if (_cwait_num)
			{
				// 叫醒消费者
				std::cout << "叫醒消费者..." << std::endl;
				_consume_cond.Notified();
			}
		}
		void Pop(T *out)
		{
			LockGuard lockguard(_mutex);
			// 你想放数据，就能放数据吗？？生产数据是有条件的！
			while (ISEmpty())
			{
				std::cout << "消费者进入等待..." << std::endl;
				_cwait_num++;
				_consume_cond.Wait(_mutex);
				_cwait_num--;
				std::cout << "消费者被唤醒" << std::endl;
			}
			// 4. if(IsEmpty())不满足 || 线程被唤醒
			*out = _q.front();
			_q.pop();
			// 肯定有空余，如果生产者队列有则唤醒
			if (_pwait_num)
			{
				std::cout << "叫醒生产者..." << std::endl;
				_production_cond.Notified();
			}
		}
		~BlockQueue()
		{
		}

	private:
		std::queue<T> _q;
		int _cap;
		Mutex _mutex;
		Cond _production_cond;
		Cond _consume_cond;
		int _cwait_num;
		int _pwait_num;
	};

	// ------------------------------------------------vesion 1
	// static const int Size = 10;
	// template <typename T>
	// class BlockQueue
	// {
	// private:
	// 	bool ISFull() { return _q.size() == _cap; }
	// 	bool ISEmpty() { return _q.empty(); }

	// public:
	// 	// 构造列表 ：， ，
	// 	BlockQueue(int cap = Size) : _cap(cap), _cwait_num(0), _pwait_num(0)
	// 	{
	// 		pthread_mutex_init(&_mutex, nullptr);
	// 		pthread_cond_init(&_production_cond, nullptr);
	// 		pthread_cond_init(&_consume_cond, nullptr);
	// 	}
	// 	void Equeue(const T &in)
	// 	{
	// 		pthread_mutex_lock(&_mutex);
	// 		// 你想放数据，就能放数据吗？？生产数据是有条件的！
	// 		// 如果满了就不放
	// 		while (ISFull())
	// 		{
	// 			std::cout << "生产者进入等待..." << std::endl;
	// 			_pwait_num++;
	// 			pthread_cond_wait(&_production_cond, &_mutex);
	// 			_pwait_num--;
	// 			std::cout << "生产者被唤醒" << std::endl;
	// 		}
	// 		// if(IsFull())不满足 || 线程被唤醒
	// 		_q.push(in); // 生产
	// 		// 肯定有数据,如果消费者队列有则唤醒
	// 		if (_cwait_num)
	// 		{
	// 			// 叫醒消费者
	// 			std::cout << "叫醒消费者..." << std::endl;
	// 			pthread_cond_signal(&_consume_cond);
	// 		}
	// 		pthread_mutex_unlock(&_mutex);
	// 	}
	// 	void Pop(T *out)
	// 	{
	// 		pthread_mutex_lock(&_mutex);
	// 		// 你想放数据，就能放数据吗？？生产数据是有条件的！
	// 		while (ISEmpty())
	// 		{
	// 			std::cout << "消费者进入等待..." << std::endl;
	// 			_cwait_num++;
	// 			pthread_cond_wait(&_consume_cond, &_mutex);
	// 			_cwait_num--;
	// 			std::cout << "消费者被唤醒" << std::endl;
	// 		}
	// 		// 4. if(IsEmpty())不满足 || 线程被唤醒
	// 		*out = _q.front();
	// 		_q.pop();
	// 		// 肯定有空余，如果生产者队列有则唤醒
	// 		if (_pwait_num)
	// 		{
	// 			std::cout << "叫醒生产者..." << std::endl;
	// 			pthread_cond_signal(&_production_cond);
	// 		}
	// 		pthread_mutex_unlock(&_mutex);
	// 	}
	// 	~BlockQueue()
	// 	{
	// 		pthread_mutex_destroy(&_mutex);
	// 		pthread_cond_destroy(&_production_cond);
	// 		pthread_cond_destroy(&_consume_cond);
	// 	}

	// private:
	// 	std::queue<T> _q;
	// 	int _cap;
	// 	pthread_mutex_t _mutex;
	// 	pthread_cond_t _production_cond;
	// 	pthread_cond_t _consume_cond;
	// 	int _cwait_num;
	// 	int _pwait_num;
	// };
}